#include "Menu.h"
#include "Sentence.h"
#include "GFuns.h"

void Menu::Init()
{
	root = nullptr;
	selected = nullptr;
	back = nullptr;
	forceBack = new MenuItem("ForceBack");

	clothes = nullptr;
	inventory = nullptr;
	buyInventory = nullptr;
	purse = nullptr;

	hero = nullptr;
	interlocutor = nullptr;
	phrase = nullptr;

	isVisible = false;
}

Menu::Menu(Character* aHero)
{
	Init();
	hero = aHero;

	root = new MenuItem("Inventory");
	inventory = root->AddMenu("Items");
	clothes = root->AddMenu("Clothes");
	purse = root->AddMenu("Purse");;
	back = root->AddMenu("Back");
	selected = root->menus.front();

	RefreshClothes();
	RefreshInventory();
	RefreshPurse();
}

Menu::Menu(Character* aHero, Character* aCharacter)
{
	Init();
	hero = aHero;
	interlocutor = aCharacter;

	interlocutorFacing = interlocutor->GetFacing();
	interlocutor->SetFacing(hero->GetPositionX(),hero->GetPositionY());

	root = new MenuItem(aCharacter->GetName());
	(root->AddMenu("Talk"))->action = ACTION_TALK;
	if(aCharacter->GetInventory()->sell.size() > 0)
		buyInventory = root->AddMenu("Buy");
	inventory = root->AddMenu("Steal");
	back = root->AddMenu("Back");
	selected = root->menus.front();

	RefreshClothes();
	RefreshInventory();

	if(interlocutor->robbed)
	{
		phrase = Phrase::CreatePhrase("Get away you thief!");
		selected = forceBack;
	}
}

Menu::Menu(Character* aHero, TileAction* aTileAction)
{
	Init();
	hero = aHero;
	tileAction = aTileAction;

	root = new MenuItem(tileAction->name);
	root->AddMenu(tileAction->GetMenu());
	back = root->AddMenu("Back");
	selected = root->menus.front();
}

Menu::~Menu()
{
	delete root;
}

void Menu::ProceedInput(Input* aInput)
{
	// Selection in menu and phrase
	if(selected != forceBack)
	{
		if(aInput->KeyPressed(ALLEGRO_KEY_W))
		{
			if(selected == selected->parent->menus.front()) selected = selected->parent->menus.back();
			else
				for(unsigned i=1; i<selected->parent->menus.size(); i++)
					if(selected == selected->parent->menus[i])
					{
						selected = selected->parent->menus[i-1];
						break;
					}
		}

		if(aInput->KeyPressed(ALLEGRO_KEY_S))
		{
			if(selected == selected->parent->menus.back()) selected = selected->parent->menus.front();
			else
				for(unsigned i=0; i<selected->parent->menus.size()-1; i++)
					if(selected == selected->parent->menus[i])
					{
						selected = selected->parent->menus[i+1];
						break;
					}
		}
	}
	else if(phrase != nullptr && phrase->options.size() > 0)
	{
		if(aInput->KeyPressed(ALLEGRO_KEY_W))
		{
			if(phrase->selected == 0)
				phrase->selected = phrase->options.size()-1;
			else
				phrase->selected--;
		}

		if(aInput->KeyPressed(ALLEGRO_KEY_S))
		{
			if(phrase->selected == phrase->options.size()-1)
				phrase->selected = 0;
			else
				phrase->selected++;
		}
	}
	
	// Choice
	if(aInput->KeyReleased(ALLEGRO_KEY_SPACE) || aInput->KeyReleased(ALLEGRO_KEY_D))
	{
		// Quest advance
		if(selected == forceBack && phrase != nullptr && phrase->IsNextQuestStatus())
			phrase->AdvanceQuestStatus();

		// Next phrase
		if(selected == forceBack && phrase != nullptr && phrase->nextPhrase != nullptr)
			phrase = phrase->nextPhrase;

		// Select option
		else if(selected == forceBack && phrase != nullptr && phrase->options.size() > 0)
			phrase = phrase->optionPhrase[phrase->selected];

		// End of talk
		else if(selected == forceBack || selected == back)
		{
			isVisible = false;
			if(interlocutor != nullptr)
				interlocutor->SetFacing(interlocutorFacing);
		}

		// Action and menu
		else
		{
			if(selected->action != ACTION_NONE) PerformAction();
			else
			{
				// in
				if(selected->menus.size() > 0)
				{
					selected->isOpen = true;
					selected = selected->menus[0]; 
				}
				// out
				else if(selected == selected->parent->menus[selected->parent->menus.size()-1])
				{
					selected = selected->parent;
					selected->isOpen = false;
				}
			}
		}
	}

	if(aInput->KeyReleased(ALLEGRO_KEY_A))
	{
		if(selected != forceBack)
		{
			if(selected->parent->parent == nullptr)
			{
				isVisible = false;
				if(interlocutor != nullptr)
					interlocutor->SetFacing(interlocutorFacing);
			}
			else
			{
				selected = selected->parent;
				selected->isOpen = false;
			}
		}
	}
}

void Menu::PerformAction()
{
	if(selected->action == ACTION_ITEM_DROP || selected->action == ACTION_ITEM_DRINK)
	{
		if(selected->action == ACTION_ITEM_DRINK)
			hero->intoxication += 0.1;

		MenuItem* item = selected->parent;
		int itemNumber = NumberInMenu(item);

		if(item->parent == clothes)
		{
			hero->GetClothes()->erase(hero->GetClothes()->begin()+itemNumber);
			RefreshClothes();
			selected = clothes->menus.front();
		}
		else
		{
			int pocketNumber = NumberInMenu(item->parent);
			hero->GetInventory()->self[pocketNumber].items.erase(hero->GetInventory()->self[pocketNumber].items.begin()+itemNumber);
			if(hero->GetInventory()->self[pocketNumber].items.size() == 0)
				hero->GetInventory()->self.erase(hero->GetInventory()->self.begin()+pocketNumber);
			RefreshInventory();
			selected = inventory->menus.front();
		}
	}
	else if(selected->action == ACTION_ITEM_TAKE_ON)
	{
		MenuItem* item = selected->parent;
		int itemNumber = NumberInMenu(item);

		hero->GetClothes()->at(itemNumber).SetEquipped(true);

		RefreshClothes();
		selected = clothes->menus.front();
	}
	else if(selected->action == ACTION_ITEM_TAKE_OFF)
	{
		MenuItem* item = selected->parent;
		int itemNumber = NumberInMenu(item);

		hero->GetClothes()->at(itemNumber).SetEquipped(false);

		RefreshClothes();
		selected = clothes->menus.front();
	}
	else if(selected->action == ACTION_ITEM_BUY)
	{
		MenuItem* item = selected->parent;
		int itemNumber = NumberInMenu(item);
		int pocketNumber = NumberInMenu(item->parent);

		Item bought = interlocutor->GetInventory()->sell[pocketNumber].items[itemNumber];
		interlocutor->GetInventory()->sell[pocketNumber].items.erase(
			interlocutor->GetInventory()->sell[pocketNumber].items.begin()+itemNumber);
		hero->GetInventory()->AddItem(bought);

		hero->SetGold(hero->GetGold()-bought.GetValue());

		RefreshInventory();
		selected = buyInventory->menus[pocketNumber];
	}
	else if(selected->action == ACTION_ITEM_STEAL)
	{
		if(rand()%2 == 0)
		{
			phrase = Phrase::CreatePhrase("Thief!");
			selected = forceBack;
			interlocutor->robbed = true;
			interlocutor->mood = MOOD_ANGRY;
			return;
		}

		MenuItem* item = selected->parent;
		int itemNumber = NumberInMenu(item);
		int pocketNumber = NumberInMenu(item->parent);

		Item stolen = interlocutor->GetInventory()->self[pocketNumber].items[itemNumber];
		interlocutor->GetInventory()->self[pocketNumber].items.erase(
			interlocutor->GetInventory()->self[pocketNumber].items.begin()+itemNumber);
		if(interlocutor->GetInventory()->self[pocketNumber].items.size() == 0)
			interlocutor->GetInventory()->self.erase(interlocutor->GetInventory()->self.begin()+pocketNumber);
		hero->GetInventory()->AddItem(stolen);

		RefreshInventory();
		selected = inventory->menus[pocketNumber];
	}
	else if(selected->action == ACTION_ITEM_TAKE)
	{
		MenuItem* item = selected->parent;
		int itemNumber = NumberInMenu(item);

		Item taken = tileAction->items[itemNumber];
		tileAction->items.erase(tileAction->items.begin() + itemNumber);
		hero->GetInventory()->AddItem(taken);
		tileAction->RefreshItems();

		if(item->parent->menus.size() == 1)
		{
			isVisible = false;
		}
		else
			selected = root->menus.front()->menus.front();
	}
	else if(selected->action == ACTION_TALK)
	{
		for(unsigned int i=0; i<interlocutor->quests.size(); i++)
		{
			if(interlocutor->quests[i]->progress != QUEST_STATUS_NEW && interlocutor->quests[i]->progress != QUEST_STATUS_DONE)
			{
				phrase = interlocutor->quests[i]->GetPhrase(interlocutor);
				if(phrase != nullptr) break;
			}
		}
		if(phrase == nullptr)
		{
			for(unsigned int i=0; i<interlocutor->quests.size(); i++)
			{
				if(interlocutor->quests[i]->progress == QUEST_STATUS_NEW)
				{
					phrase = interlocutor->quests[i]->GetPhrase(interlocutor);
					if(phrase != nullptr) break;
				}
			}
		}
		if(phrase == nullptr)
		{
			phrase = Sentence::GetSentence(interlocutor);
		}
		selected = forceBack;
	}
	
}

void Menu::SetVisible(bool aVisible)
{
	if(!isVisible)
	{
		RefreshClothes();
		RefreshInventory();
		RefreshPurse();
		isVisible = true;

		if(selected != forceBack)
			selected = root->menus.front();
	}
	else 
		isVisible = false;
}

unsigned int Menu::NumberInMenu(MenuItem* aMenu)
{
	for(unsigned int i=0; i<aMenu->parent->menus.size()-1; i++)
		if(aMenu == aMenu->parent->menus[i])
			return i;

	return 0;
}

void Menu::RefreshInventory()
{
	MenuItem* tempInventory = inventory;
	for(int inv=0; inv<2; inv++)
	{
		if(inv == 1) inventory = buyInventory;

		if(inventory != nullptr)
		{
			inventory->menus.clear();

			vector<Pocket>* pockets;
			if(interlocutor == nullptr)
				pockets = &(hero->GetInventory()->self);
			else if(inv == 0)
				pockets = &(interlocutor->GetInventory()->self);
			else
				pockets = &(interlocutor->GetInventory()->sell);

			for(unsigned int p=0; p<pockets->size(); p++)
			{
				MenuItem* currentMenu = inventory->AddMenu(pockets->at(p).name);

				vector<Item>* vec = &(pockets->at(p).items);
				for(unsigned int i=0; i<vec->size(); i++)
				{
					Item* item = &(vec->at(i));
					MenuItem* added;
					if(inv == 1)
					{
						string itemToBuy = item->GetName();
						itemToBuy += " (";
						itemToBuy += iToString(item->GetValue());
						itemToBuy += "G)";
						added = currentMenu->AddMenu(itemToBuy);

						if(hero->GetGold() >= item->GetValue())
							(added->AddMenu("Buy"))->action = ACTION_ITEM_BUY;
						else
							added->AddMenu("Need more Gold");
						
						added->AddMenu("Back");
					}
					else
					{
						added = currentMenu->AddMenu(item->GetName());
						if(interlocutor == nullptr)
						{
							if(item->GetItemType() == ITEM_DRINK)
								(added->AddMenu("Drink"))->action = ACTION_ITEM_DRINK;
							(added->AddMenu("Drop"))->action = ACTION_ITEM_DROP;
							added->AddMenu("Back");
						}
						else
						{
							(added->AddMenu("Steal"))->action = ACTION_ITEM_STEAL;
							added->AddMenu("Back");
						}
					}

					if(item->IsEquipped())
						added->isEquipped = true;
				}
				currentMenu->AddMenu("Back");
			}
			inventory->AddMenu("Back");
		}
	}
	inventory = tempInventory;
}

void Menu::RefreshClothes()
{
	if(clothes != nullptr)
	{
		clothes->menus.clear();

		vector<Item>* vec = hero->GetClothes();
		for(unsigned int i=0; i<vec->size(); i++)
		{
			Item* item = &(vec->at(i));
			MenuItem* added = clothes->AddMenu(item->GetName());
			if(item->IsEquipped())
			{
				added->isEquipped = true;
				(added->AddMenu("Take off"))->action = ACTION_ITEM_TAKE_OFF;
				(added->AddMenu("Drop"))->action = ACTION_ITEM_DROP;
				added->AddMenu("Back");
			}
			else
			{
				(added->AddMenu("Take on"))->action = ACTION_ITEM_TAKE_ON;
				(added->AddMenu("Drop"))->action = ACTION_ITEM_DROP;
				added->AddMenu("Back");
			}
		}
		clothes->AddMenu("Back");
	}
}

void Menu::RefreshPurse()
{
	if(purse != nullptr)
	{
		purse->menus.clear();

		char goldBuf[10];
		_itoa(hero->GetGold(),goldBuf,10);
		strcat(goldBuf," G");

		purse->AddMenu(goldBuf);
		purse->AddMenu("Back");
	}
}